import json

from django.views import View
from django.http import JsonResponse
from django_redis import get_redis_connection

from apps.goods.models import SKU
from shopping_mall.utils.cookiesecret import CookieSecret

# 添加购物车
class CartsView(View):

    # 添加购物车
    def post(self, request):

        # 1：提取参数
        user = request.user
        data = json.loads(request.body.decode())
        sku_id = data.get('sku_id')
        count = data.get('count')
        selected = data.get('selected', True)

        # 2:校验参数
        # 存在性校验
        if not all([sku_id, count]):
            return JsonResponse({
                "code": "400",
                "errmsg": "参数缺失"
            })
        # 查看商品的id是否存在，以及是否下架了
        try:
            SKU.objects.get(pk=sku_id, is_launched=True)
        except SKU.DoesNotExist as e:
            return JsonResponse({
                "code": 400,
                "errmsg": "商品不存在或者已经下架了"
            })
        # 判断传入的count是不是整数
        try:
            count = int(count)
        except Exception as e:
            return JsonResponse({
                "code": 400,
                "errmsg": "您输入的不是整数"
            })
        # 判断selected 是不是整数
        if not isinstance(selected,bool):
            return JsonResponse({
                "code" : 400,
                "errmsg": "selectde不是bool类型"
            })
            # 3：数据处理---判断用户是否登陆，划分两部分
            # 如果用户登陆了，使用哈希存储商品的id和商品的数量，使用集合存储选中的商品的id
            # 如果用户没有登陆，
            # 用户登陆了
        if user.is_authenticated:
            # 连接数据库
            conn = get_redis_connection("carts")
            # 用哈希存储商品的id和数量,使用carts_用户id，作为哈希的键
            conn.hincrby(
                'carts_%d' % user.id,
                sku_id,
                count,
            )
            # 选中信息在redis中用一个集合来存，在集合内部的就是选中的，没有在集合里的就是没有选中的。
            # 集合的键就是select_用户id  ,内部值是sku的id
            if selected:
                conn.sadd(
                    'selected_%d' % user.id,
                    sku_id,
                )
            else:
                conn.srem(
                    'selected_%d' % user.id,
                    sku_id,
                )
            return JsonResponse({
                'code': 0,
                'errmsg': "ok",
            })
        else:
            # 1：获取请求中的cookie
            cookie_carts = request.COOKIES.get('carts')
            # 两种情况，购物车数据存在或者不存在。
            if cookie_carts:
                # 2:传入自定义的 CookieSecret中解码成字典类型
                cart_dict = CookieSecret.loads(cookie_carts)

                # 3:判断新增的sku商品是否在原来的cookie 购物车中，如果存在则进行数量的累加，如果不存在则新建
                if sku_id in cart_dict:
                    cart_dict[sku_id]['count'] += count
                    cart_dict[sku_id]['selected'] = selected

                else:
                    # 新增这个商品
                    cart_dict[sku_id] = {
                        'count': count,
                        'selected': selected
                    }

            # 如果购物车不存在，重新构建商品字典集合
            else:
                cart_dict = {}
                cart_dict[sku_id] = {
                    'count': count,
                    'selected': selected,
                }

            # 对购物车的字典数据进行编码，然后构建响应返回
            cookie_str = CookieSecret.dumps(cart_dict)

            response = JsonResponse({
                'code': 0,
                'errmsg': 'ok',
            })

            response.set_cookie(
                'carts',
                cookie_str
            )

            return response



    # 展示购物车接口：
    def get(self, request):

        user = request.user
        # 不管是从redis数据库中读数据还是从cookie中读取数据，都组织成字典格式
        # cart_dict = {1: {"count": 5, "selected": True}}
        cart_dict = {}

        # 如果用户登陆了
        if user.is_authenticated:
            # 1： 获取连接对象
            conn = get_redis_connection('carts')
            # 2:读取该用户的商品id和商品数量（哈希的键是carts_用户的id）
            skus_dict = conn.hgetall('carts_%s' % user.id)
            # {b"1": b"5", b"2": b"15"}读取的数据类似这样。编号为1的商品有5本

            # 3：读取该用户商品哪些是被选中的。
            skus_selected = conn.smembers("selected_%s" % user.id)

            # 4:构造字典格式：
            for k, v in skus_dict.items():
                cart_dict[int(k)] = {
                    'count': int(v),
                    'selected': k in skus_selected
                }
        # 如果用户没有登陆
        else:
            cookie_carts = request.COOKIES.get('carts')

            if cookie_carts:
                cart_dict = CookieSecret.loads(cookie_carts)

        cart_skus = []

        # 根据字典数据查找sku商品的详细信息
        for k, v in cart_dict.items():
            # 拿到商品的具体对象 # k: 1; v: {"count": 5, "selected": True}
            sku = SKU.objects.get(pk=k)

            cart_skus.append(
                {
                    'id': sku.id,  # 商品的id
                    'name': sku.name,  # 商品名
                    'default_image_url': sku.default_image.url,  # 拿到图片的路径
                    'price': sku.price,  # 拿到商品的价格
                    'count': v['count'],  # 拿到商品的数量
                    'selected': v['selected']  # 拿到商品是否被选中的属性
                }
            )
        return JsonResponse({
            'code': 0,
            'errmsg': 'ok',
            'cart_skus': cart_skus
        })

    # 修改购物车
    def put(self, request):
        user = request.user

        # 1、提取参数
        data = json.loads(request.body.decode())
        sku_id = data.get('sku_id')
        count = data.get('count')
        selected = data.get('selected', True)

        # 2、校验参数
        if not all([sku_id, count]):
            return JsonResponse({'code': 400, 'errmsg': '缺少参数'}, status=400)

        try:
            SKU.objects.get(pk=sku_id, is_launched=True)
        except SKU.DoesNotExist as e:
            print(e)
            return JsonResponse({'code': 404, 'errmsg': 'sku不存在'}, status=404)

        try:
            # count = int("5")
            count = int(count)
        except Exception as e:
            print(e)
            return JsonResponse({'code': 404, 'errmsg': 'count参数有误'}, status=400)

        if not isinstance(selected, bool):
            return JsonResponse({'code': 404, 'errmsg': 'selected参数有误'}, status=400)

        # 3、业务/数据处理 —— 修改redis or 修改cookie
        if user.is_authenticated:
            # 登陆状态,修改redis购物车数据
            conn = get_redis_connection('carts')
            # 商品数据：hash对象{16: 4}; 勾选状态：集合[16]
            conn.hset(
                'carts_%d' % user.id,
                sku_id,
                count
            )
            if selected:
                conn.sadd('selected_%d'%user.id, sku_id)
            else:
                conn.srem('selected_%d' % user.id, sku_id)

            return JsonResponse({
                'code': 0,
                'errmsg': 'ok',
                'cart_sku': {
                    'sku_id': sku_id,
                    'count': count,
                    'selected': selected
                }
            })

        else:
            # 未登陆，修改cookie购物车数据
            # 购物车字典格式{1: {"count": 5, "selected": True}}
            cart_dict = None # 改变是用来记录cookie中解码出来的购物车字典数据，如果cookie没有购物车该变量设置为空字典
            cookie_carts = request.COOKIES.get('carts') # "ASjibgrehgbBHBHlbgre=" or None
            if cookie_carts:
                cart_dict = CookieSecret.loads(cookie_carts) # 解码得出字典数据
            else:
                cart_dict = {}

            # 修改购物车字典数据，重新写入cookie返回
            cart_dict[sku_id] = {
                'count': count,
                'selected': selected
            }

            # 编码购物车数据设置到cookie中
            cookie_carts = CookieSecret.dumps(cart_dict)
            response = JsonResponse({
                'code': 0,
                'errmsg': 'ok',
                'cart_sku': {
                    'sku_id': sku_id,
                    'count': count,
                    'selected': selected
                }
            })
            response.set_cookie(
                'carts',
                cookie_carts
            )
            return response

    def delete(self, request):
        user = request.user
        data = json.loads(request.body.decode())
        sku_id = data.get('sku_id')

        if user.is_authenticated:
            # 1、登陆，删除redis购物车
            # 商品和数量哈希对象：carts_1 : {1: 5}
            # 选中状态集合对象：[1]
            conn = get_redis_connection('carts')
            conn.hdel('carts_%d' % user.id, sku_id)
            conn.srem('selected_%d' % user.id, sku_id)
            return JsonResponse({'code': 0, 'errmsg': 'ok'})
        else:
            # 2、未登陆，删除cookie购物车
            # 2.1、先读cookie购物车数据
            cookie_carts = request.COOKIES.get('carts')
            if cookie_carts:
                # 2.2、解码出购物车字典格式数据
                cart_dict = CookieSecret.loads(cookie_carts)
            else:
                cart_dict = {}

            # 2.3、在字典数据中删除当前sku商品
            # del cart_dict[sku_id] or cart_dict.pop(sku_id) # 如果key不存在会报异常KeyError
            try:
                cart_dict.pop(sku_id)
            except KeyError as e:
                print(e)
                return JsonResponse({'code': 400, 'errmsg': '删除错误！'})

            # 2.4、重新编码写入cookie
            cookie_carts = CookieSecret.dumps(cart_dict)
            response = JsonResponse({'code': 0, 'errmsg': 'ok！'})
            response.set_cookie(
                'carts',
                cookie_carts
            )
            return response


# 全选购物车接口的实现
class CartsSelectAllView(View):
    def put(self, request):

        user = request.user
        # 1:提取参数
        data = json.loads(request.body.decode())
        selected = data.get("selected", True)
        # 2：校验参数---校验selected是不是bool类型
        if not isinstance(selected, bool):
            return JsonResponse({
                "code": 400,
                "errmsg": "数据类型错误"
            }, status=400)

        # 3: 业务处理---将所有的sku商品的selected修改为True
        # 思路：如果用户登陆了---1：获取购物车中的所有商品---2：将所有的商品的selected修改为True或者False
        if user.is_authenticated:
            # 1:获取redis数据库连接
            conn = get_redis_connection('carts')

            # 2:根据用户id获取所有的购物车中的sku商品(字节集合)
            cart_dict = conn.hgetall("carts_%d" % user.id)

            # 3:获取购物车集合所有的键（sku_id）
            sku_ids = cart_dict.keys()

            # 4:如果选中则根据键集合，全部修改选中集合。
            if selected:
                conn.sadd("selected_%d"% user.id, *sku_ids)
            else:
                conn.srem("selected_%d"% user.id, *sku_ids)

            # 4:构建响应返回
            return JsonResponse({
                "code": 0,
                "errmsg": "ok"
            })

        # 用户没有登陆---修改cookie中的购物车
        else:
            # 思路：1：提取cookie中的购物车数据，并解密成字典。---2：修改购物车的选中字段---3：重新构建响应返回

            # 1：提取购物车数据,并解密
            cookie_carts = request.COOKIES.get("carts")
            if cookie_carts:
                cart_dict = CookieSecret.loads(cookie_carts)
            else:
                cart_dict = {}

            # 2:修改购物车选中字段

            # 获取所有的键
            sku_ids = cart_dict.keys()
            for sku_id in sku_ids:
                # 如果传入的是false 则全部写入false
                cart_dict[sku_id]['selected'] = selected

            # 3: 重新编码cookie数据
            cookie_carts = CookieSecret.dumps(cart_dict)
            response = JsonResponse({
                'code': 0,
                'errmsg': "ok"
            })
            response.set_cookie(
                'carts',
                cookie_carts
            )
            return response


